#pragma once
#include <pthread.h>
#include <vector>
#include <semaphore.h>
#include "task.hpp"

namespace ns_ring_queue
{
    const int default_cap = 10;

    template <class T>
    class RingQueue
    {
    private:
        sem_t _black_sem;             //空格资源
        sem_t _data_sem;              //数据资源
        std::vector<T> ring_queue;    //环行队列
        int _cap;                      //环行队列的容量
        int _c_step;                  //消费者的当前下标
        int _p_step;                  //生产者的当前下标
        pthread_mutex_t p_mtx;        //生产者的锁
        pthread_mutex_t c_mtx;        //消费者的锁
    public:
        RingQueue(const int cap = default_cap) : _c_step(0), _p_step(0), ring_queue(cap), _cap(cap)
        {
            sem_init(&_black_sem, 0, _cap);
            sem_init(&_data_sem, 0, 0);
            pthread_mutex_init(&c_mtx, nullptr);
            pthread_mutex_init(&p_mtx, nullptr);
        }

        void push(const T& in)
        {
            sem_wait(&_black_sem);

            pthread_mutex_lock(&p_mtx);
            ring_queue[_p_step] = in;
            ++_p_step;
            _p_step %= _cap;
            pthread_mutex_unlock(&p_mtx);

            sem_post(&_data_sem);
        }

        void pop(T* out)
        {
            sem_wait(&_data_sem);

            pthread_mutex_lock(&c_mtx);
            *out = ring_queue[_c_step];
            ++_c_step;
            _c_step %= _cap;
            pthread_mutex_unlock(&c_mtx);

            sem_post(&_black_sem);
        }

        ~RingQueue()
        {
            sem_destroy(&_black_sem);
            sem_destroy(&_data_sem);
            pthread_mutex_destroy(&c_mtx);
            pthread_mutex_destroy(&p_mtx);
        }
    };
}